package com.xxj.puzzlesheep;

import com.xxj.puzzlesheep.core.ILScreen;
import com.xxj.puzzlesheep.core.LGraphics;
import com.xxj.puzzlesheep.core.LHandler;
import com.xxj.puzzlesheep.core.LImage;
import com.xxj.puzzlesheep.core.LSystem;
import com.xxj.puzzlesheep.core.LTimerContext;
import com.xxj.puzzlesheep.util.LGraphicsUtils;

import android.app.Activity;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

/**
 * 
 * @author a322496
 *
 */
public class PuzzleView extends SurfaceView implements SurfaceHolder.Callback {

	// SurfaceView继承自View

	private final static long MAX_INTERVAL = 1000L;

	final static private int fpsX = 5;

	final static private int fpsY = 20;

	private transient boolean start, isFPS, running;

	private transient int width, height;

	private transient long maxFrames, curTime, startTime, offsetTime, curFPS,
			calcInterval;

	private transient double frameCount;

	private SurfaceHolder surfaceHolder;

	private CanvasThread mainLoop;

	private LImage screen;

	private LGraphics canvasGraphics;

	private LHandler handler;

	private Rect rect;

	public PuzzleView(Activity activity) {
		this(activity, false);
	}

	public PuzzleView(Activity activity, boolean isLandscape) {
		super(activity.getApplicationContext());
		LSystem.gc();
		LSystem.setupHandler(activity, this);
		this.handler = LSystem.getSystemHandler();
		this.setFullscreen();
		this.handler.setLandscape(isLandscape);
		this.setOnCreateContextMenuListener(handler);
		this.setOnClickListener(handler);
		this.setOnFocusChangeListener(handler);
		this.setOnKeyListener(handler);
		this.setOnLongClickListener(handler);
		this.setOnTouchListener(handler);
		this.screen = new LImage(width = handler.getWidth(), height = handler
				.getHeight());
		this.rect = new Rect(0, 0, width, height);
		System.out.println("width=" + width + ",height=" + height);
		this.mainLoop = new CanvasThread();
		this.surfaceHolder = getHolder();
		this.surfaceHolder.addCallback(this);
		this.surfaceHolder.setSizeFromLayout();
		this.setRunning(true);
		this.setFPS(LSystem.DEFAULT_MAX_FPS);
		this.canvasGraphics = screen.getLAGraphics();
		this.setFocusable(true);
		this.setFocusableInTouchMode(true);
		this.requestFocus();
	}

	public void setFullscreen() {
		handler.setFullscreen();
	}

	public void setScreen(ILScreen screen) {
		this.handler.setScreen(screen);
	}

	public void destroyView() {
		if (mainLoop != null) {
			mainLoop = null;
		}
		LGraphicsUtils.destroyImages();
		LSystem.gc();
	}

	class CanvasThread extends Thread {
		public void run() {
			final LTimerContext timerContext = new LTimerContext();
			timerContext.setTimeMillis(startTime = System.currentTimeMillis());
			ILScreen iscreen = null;
			Canvas canvas = null;
			do {
				if (!start) {
					continue;
				}
				iscreen = handler.getScreen();
				canvasGraphics.drawClear();
				iscreen.createUI(canvasGraphics);
				curTime = System.currentTimeMillis();
				timerContext.setTimeSinceLastUpdate(curTime
						- timerContext.getTimeMillis());
				timerContext.setSleepTimeMillis((offsetTime - timerContext
						.getTimeSinceLastUpdate())
						- timerContext.getOverSleepTimeMillis());
				if (timerContext.getSleepTimeMillis() > 0) {
					try {
						Thread.sleep(timerContext.getSleepTimeMillis());
					} catch (InterruptedException e) {
					}
					timerContext.setOverSleepTimeMillis((System
							.currentTimeMillis() - curTime)
							- timerContext.getSleepTimeMillis());
				} else {
					timerContext.setOverSleepTimeMillis(0L);
				}
				timerContext.setTimeMillis(System.currentTimeMillis());
				iscreen.runTimer(timerContext);
				if (isFPS) {
					tickFrames();
					canvasGraphics.setColor(Color.WHITE);
					canvasGraphics.setAntiAlias(true);
					canvasGraphics.drawString(("FPS:" + curFPS).intern(), fpsX,
							fpsY);
					canvasGraphics.setAntiAlias(false);
				}
				canvas = surfaceHolder.lockCanvas(rect);
				canvas.drawBitmap(screen.getBitmap(), 0, 0, null);
				surfaceHolder.unlockCanvasAndPost(canvas);
				if (isFocusable()) {
					continue;
				}
				try {
					Thread.sleep(30);
				} catch (InterruptedException e) {
				}
				LSystem.gc(10000, 1);
			} while (running);
			destroyView();
		}

		private void tickFrames() {
			frameCount++;
			calcInterval += offsetTime;
			if (calcInterval >= MAX_INTERVAL) {
				long timeNow = System.currentTimeMillis();
				long realElapsedTime = timeNow - startTime;
				curFPS = (long) ((frameCount / realElapsedTime) * MAX_INTERVAL);
				frameCount = 0L;
				calcInterval = 0L;
				startTime = timeNow;
			}
		}

	}

	public Thread getMainLoop() {
		return mainLoop;
	}

	public void mainLoop() {
		this.handler.getActivity().setContentView(this);
		this.startPaint();
	}

	public void mainStop() {
		this.endPaint();
	}

	public void startPaint() {
		this.start = true;
	}

	public void endPaint() {
		this.start = false;
	}

	public void setFPS(long frames) {
		this.maxFrames = frames;
		this.offsetTime = (long) (1.0 / maxFrames * MAX_INTERVAL);
	}

	public long getMaxFPS() {
		return this.maxFrames;
	}

	public long getCurrentFPS() {
		return this.curFPS;
	}

	public void setShowFPS(boolean isFPS) {
		this.isFPS = isFPS;
	}

	public boolean isRunning() {
		return running;
	}

	public void setRunning(boolean running) {
		this.running = running;
	}

	public LHandler getLHandler() {
		return handler;
	}

	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		holder.setFixedSize(width, height);
	}

	public void surfaceCreated(SurfaceHolder holder) {
		mainLoop.start();
	}

	public void surfaceDestroyed(SurfaceHolder holder) {
		boolean result = true;
		setRunning(false);
		while (result) {
			try {
				if (null != mainLoop) {
					mainLoop.join();
				}
				result = false;
			} catch (InterruptedException e) {
			}
		}
		mainLoop = null;
	}

}
